#pragma once 

#include<iostream>
#include<pthread.h>
#include<queue>

namespace ns_BlockQueue
{
    const int default_cap = 5;
    template<class T>
    class BlockQueue
    {
    public:
        BlockQueue(int cap = default_cap):
        _cap(cap)
        {
            //初始化锁和条件变量
            pthread_mutex_init(&_mutex,nullptr);
            pthread_cond_init(&_isfull,nullptr);
            pthread_cond_init(&_isempty,nullptr);
        }
        ~BlockQueue(){
            //销毁锁和条件变量
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_isfull);
            pthread_cond_destroy(&_isempty);
        }
    private:
        std::queue<int> _sq;  
        int _cap; //队列容量
        pthread_mutex_t _mutex; //锁
        pthread_cond_t _isfull; //判断是否满
        pthread_cond_t _isempty;  //判断是否空
    
    private:
        bool _Is_full()
        {
            return _sq.size() == _cap;    
        }
        bool _Is_empty()
        {
            return _sq.size() == 0;
        }
        void LockQueue()
        {
            pthread_mutex_lock(&_mutex);
        }
        void UnLockQueue()
        {
            pthread_mutex_unlock(&_mutex);
        }
        void ProducerWait()
        {
            pthread_cond_wait(&_isempty,&_mutex); //生产者等待
        }
        void ConsumerWait()
        {
            pthread_cond_wait(&_isfull,&_mutex); //消费者等待
        }
        void WakeupProducer()
        {
            //唤醒生产者
            pthread_cond_signal(&_isempty);
        }
        void WakeupConsumer()
        {
            //唤醒消费者
            pthread_cond_signal(&_isfull);
        }
    public:
        void push(const T& in)
        {
            //生产者生产
            //上锁
            LockQueue();
            while(_Is_full()) //满了停止生产
            {
                //等待消费者消费
                ProducerWait();
            }
            //存入数据
            _sq.push(in);
            //唤醒消费者
            WakeupConsumer();
            //解锁
            UnLockQueue();
        }
        void pop(T* out)
        {
            //消费者消费
            UnLockQueue(); 
            while(_Is_empty())
            {
                ConsumerWait();
            }
            *out = _sq.front();
            _sq.pop();
            WakeupProducer();
            UnLockQueue();
        }
    };
}